﻿namespace FFF.Test.Application.AppServices.FW
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Text;
    using System.Linq;
    using System.Threading.Tasks;
    using Abp.Application.Services;
    using Abp.Application.Services.Dto;
    using Abp.Authorization;
    using Abp.UI;
    using Abp.Domain.Uow;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Abp.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;
    using AutoMapper.QueryableExtensions;
    using FFF.Test.Application.AppServices;
    using FFF.Test.Application.DomainServices;
    using FFF.Test.DataAccess.Framework;
    using FFF.Test.Application.AppServices.PublicService.Sessions;
    using FFF.Test.Application.Framework.Dto;
    using Ydm.Helper;
    using Ydm.Extensions;
    using FFF.Test.Application.PublicService.AppService.TreeGrid;
    using FFF.Test.Application.DomainServices.FW;
    using FFF.Test.Application.Repositories.FW;
    using FFF.Test.Entity.FW;
    using FFF.Test.Entity.FW.Dto;
    using FFF.Test.Entity.FW.View;
    using Microsoft.AspNetCore.Http;
    using Abp.Dependency;
    using FFF.Test.Application.AppServices.PublicService.Token;
    using FFF.Test.Util.Consts;
    using Abp.Web.Models;
    using FFF.Test.Application.AppServices.PublicService.Grid;
    using FFF.Test.Application.AppServices.PublicService.VerificationCode;
    using Newtonsoft.Json;

    /// <summary>
    /// 用户表应用层服务
    /// </summary>
    [YdmApiVersion(Version = "FW")]
    public class FWUserAppService : YdmAbpCurdAppServiceBase<FWUserEntity, Guid, FWUserCreateInputDto, FWUserUpdateInputDto, FWUserDto, ViewFWUser, ViewFWUser>, IFWUserAppService
    {
        private readonly IFWUserDomainService _fWUserDomainService;

        private readonly IFWUserRepository _fWUserRepository;
        private readonly IFWLoginLogRepository _fWLoginLogRepository;

        private readonly ISessionAppService _sessionAppservice;
        private readonly ITokenAuthService _tokenAuthService;

        private readonly IVerificationCodeAppService _verificationCodeAppService;

        /// <summary>
        /// 依赖注入容器
        /// </summary>
        public IIocResolver IocResolver { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="FWUserAppService"/> class.
        /// 构造方法
        /// </summary>
        /// <param name="fWUserRepository">用户表仓储</param>
        /// <param name="fWUserDomainService">用户表领域层</param>
        /// <param name="tokenAuthService">tokneservice</param>
        /// <param name="sessionAppservice">session</param>
        /// <param name="fWLoginLogRepository">登陆日志仓储</param>
        /// <param name="verificationCodeAppService">verificationCodeAppService</param>
        public FWUserAppService(
            IFWUserRepository fWUserRepository,
            IFWUserDomainService fWUserDomainService,
            ITokenAuthService tokenAuthService,
            ISessionAppService sessionAppservice,
            IFWLoginLogRepository fWLoginLogRepository,
            IVerificationCodeAppService verificationCodeAppService
        )
        {
            this._fWUserRepository = fWUserRepository;
            this._fWUserDomainService = fWUserDomainService;
            this._sessionAppservice = sessionAppservice;
            this._tokenAuthService = tokenAuthService;
            this._fWLoginLogRepository = fWLoginLogRepository;
            this._verificationCodeAppService = verificationCodeAppService;
        }

        /// <summary>
        /// 2.001 注册用户(于大明)
        /// </summary>
        /// <param name="inDto">注册用户输入dto</param>
        /// <returns>注册用户输出dto</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: false)]
        [AllowAnonymous]
        public async Task<RegisterUserOutDto> RegisterUser(RegisterUserInDto inDto)
        {
            var ssmsCode = await this._sessionAppservice.GetSmmsCode();
            if (inDto.Vercode.ToLower() != ssmsCode)
            {
                throw new UserFriendlyException("用户验证码错误");
            }

            if (inDto.Password != inDto.Repass)
            {
                throw new UserFriendlyException("两次密码不一致");
            }

            var result = await this._fWUserDomainService.RegisterUserAsync(inDto);
            return result;
        }

        /// <summary>
        /// 1.009 通过手机号修改密码(于大明)
        /// </summary>
        /// <param name="inDto">通过手机号修改密码输入dto</param>
        /// <returns>通过手机号修改密码输出dto</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: false)]
        [AllowAnonymous]
        public async Task<UpdatePwdByPhoneOutDto> UpdatePwdByPhone(UpdatePwdByPhoneInDto inDto)
        {
            var ssmsCode = await this._sessionAppservice.GetSmmsCode();
            if (inDto.Vercode.ToLower() != ssmsCode)
            {
                throw new UserFriendlyException("用户验证码错误");
            }

            var result = await this._fWUserRepository.UpdatePwdByPhoneAsync(inDto);
            return result;
        }

        /// <summary>
        /// 1.004 获取站内模块信息(于大明)
        /// </summary>
        /// <param name="inDto">获取站内模块信息输入dto</param>
        /// <returns>获取站内模块信息输出dto</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: false)]
        public async Task<GetUserSetFunctionOutDto> GetUserSetFunction(GetUserSetFunctionInDto inDto)
        {
            var result = await this._fWUserDomainService.GetUserSetFunctionAsync(inDto);
            return result;
        }

        /// <summary>
        /// 1.003 用户登录(于大明)
        /// </summary>
        /// <param name="inDto">用户登录输入dto</param>
        /// <returns>用户登录输出dto</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: false)]
        [AllowAnonymous]
        public async Task<UserLoginOutDto> UserLogin(UserLoginInDto inDto)
        {
            HttpContext httpContext = this.IocResolver.Resolve<IHttpContextAccessor>().HttpContext;
            UserLoginOutDto result = new UserLoginOutDto();

            // 记录IP地址
            var ip = httpContext.Connection.RemoteIpAddress.ToString();

            var erroCount = await this._fWLoginLogRepository.GetErrorCount(inDto.UserName, ip);

            if (erroCount > 3)
            {
                if (inDto.VerificationCode.ToLower() != await this._sessionAppservice.GetValidateCode())
                {
                    result.ErrorMsg = base.L("验证码错误");
                    result.IsNeedValidateCode = true;
                    return result;
                }
            }

            ViewFWUser viewUser = await this._fWUserRepository.UserLoginAsync(inDto);

            // 登陆不成功插入登陆日志
            if (viewUser == null)
            {
                FWLoginLogCreateInputDto fWLoginLogCreateInputDto = new FWLoginLogCreateInputDto()
                {
                    UserCode = inDto.UserName,
                    UserIP = ip
                };
                await this._fWLoginLogRepository.CreateByDtoAsync(fWLoginLogCreateInputDto);
                result.IsNeedValidateCode = erroCount >= 3;
                result.ErrorMsg = base.L("用户名或密码错误");

                // 需要刷新下验证码,防止单个验证码重复登陆
                await this._verificationCodeAppService.GenVerificationCode();
                return result;
            }

            if (httpContext != null)
            {
                // 插入到session中
                httpContext.Session.SetUserInfo(viewUser);
            }

            httpContext.Session.SetString("layim_uid", viewUser.UserIntID.ToString());

            result.LoginDto = base.ObjectMapper.Map<UserLoginDto>(viewUser);
            if (!inDto.Password.EndsWith("=="))
            {
                result.LoginDto.UserPwdEncry = YdmEncrypt.Md5(inDto.Password);
            }
            else
            {
                result.LoginDto.UserPwdEncry = inDto.Password;
            }

            this.RefreshToken();
            return result;

        }

        /// <summary>
        /// 2.002 用户退出登录(于大明)
        /// </summary>
        [HttpPost]
        [Authorize(Roles = "admin")]
        public void UserLoginOut()
        {
            HttpContext httpContext = this.IocResolver.Resolve<IHttpContextAccessor>().HttpContext;

            // 清空用户登录sseeion
            httpContext.Session.RemoveUserInfo();
        }

        #region 框架方法

        /// <summary>
        /// 导入表格数据
        /// </summary>
        /// <param name="inDto">获取导出表格数据输入dto</param>
        /// <returns>dto对象</returns>
        [HttpPost]
        [UnitOfWork(isTransactional: true)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "01")]
        public override async Task<ImportOutDto> ImportExcel(ImportInDto inDto)
        {
            var outDto = await this._fWUserRepository.ImportExcelAsync(inDto);
            return outDto;
        }

        /// <summary>
        /// 导出表格数据
        /// </summary>
        /// <param name="inDto">获取导出表格数据输入dto</param>
        /// <returns>dto对象</returns>
        [HttpGet]
        [WrapResult(WrapOnSuccess = false, WrapOnError = false)]
        [UnitOfWork(isTransactional: false)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "92")]
        public override async Task<FileContentResult> GetGridExcel(GetGridListInDto inDto)
        {
            var fileResult = await this._fWUserRepository.GetGridExcelAsync(inDto);
            return fileResult;
        }

        /// <summary>
        /// 获取 表格数据
        /// </summary>
        /// <param name="inDto">表格数据输入的Dto</param>
        /// <returns>分页信息</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: false)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "00")]
        public override async Task<GridResult> GetGridDto(GetGridListInDto inDto)
        {
            var gridResult = await this._fWUserRepository.GetGridDtoAsync(inDto);
            return gridResult;
        }

        /// <summary>
        /// 获取单个  [用户表] 视图的dto
        /// </summary>
        /// <param name="idDto">idDto集合</param>
        /// <returns>单个对象的dto</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: false)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "00")]
        public override async Task<ViewFWUser> GetViewDto(PrimaryDto idDto)
        {
            var id = (Guid)idDto.Id.CastType(typeof(Guid));
            var dto = await this._fWUserRepository.GetViewDtoAsync(id);
            return dto;
        }

        /// <summary>
        /// 获取  [用户表] 视图分页的信息
        /// </summary>
        /// <param name="pagedInputDto">分页输入的Dto</param>
        /// <returns>分页信息</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: false)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "00")]
        public override async Task<MyPagedResult<ViewFWUser>> GetViewPage(PagedInputDto pagedInputDto)
        {
            var pagedResult = await this._fWUserRepository.GetViewPageAsync(pagedInputDto);
            return pagedResult;
        }

        /// <summary>
        /// 创建  [用户表]
        /// </summary>
        /// <param name="input">创建输入实体</param>
        /// <returns>输出dto</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: true)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "01")]
        public override async Task<FWUserDto> CreateByDto(FWUserCreateInputDto input)
        {
            var dto = await this._fWUserRepository.CreateByDtoAsync(input);
            return dto;
        }

        /// <summary>
        /// 更新  [用户表]
        /// </summary>
        /// <param name="input">更新的实体的对象</param>
        /// <returns>更新后的对象</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: true)]
        public override async Task<FWUserDto> UpdateByDto(FWUserUpdateInputDto input)
        {
            var dto = await this._fWUserRepository.UpdateByDtoAsync(input);

            if (input.DefaultApplicationGUID != null || input.DefaultBuUnitGUID != null)
            {
                this.RefreshToken(input.DefaultBuUnitGUID, input.DefaultCompanyGUID, input.DefaultApplicationGUID);
            }

            return dto;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="idDto">idDto集合</param>
        /// <returns>空</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: true)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "03")]
        public override async Task DeleteByDto(PrimaryDto idDto)
        {
            var id = (Guid)idDto.Id.CastType(typeof(Guid));
            await this._fWUserRepository.DeleteByIdAsync(id);
        }

        /// <summary>
        /// 批量删除  [用户表] 传递包含id的dto
        /// </summary>
        /// <param name="idDto">idDto集合</param>
        /// <returns> task 空值</returns>
        [HttpPost]
        [Authorize(Roles = "admin")]
        [UnitOfWork(isTransactional: true)]
        [YdmApiAuthor(FunctionCode = "FW_User", ActionCode = "04")]
        public override async Task BatchDelete(PrimaryDto idDto)
        {
            string strId = idDto.Id;
            IEnumerable<string> ids = strId.Split(",").Select(x => x.Replace("'", string.Empty));
            List<Guid> newIds = new List<Guid>();
            foreach (var id in ids)
            {
                await this._fWUserRepository.DeleteAsync((Guid)id.CastType(typeof(Guid)));
            }
        }
        #endregion

        private void RefreshToken(Guid? buGUID = null, Guid? companyGUID = null, Guid? applicationGUID = null)
        {
            HttpContext httpContext = this.IocResolver.Resolve<IHttpContextAccessor>().HttpContext;

            ViewFWUser viewUser = httpContext.Session.GetUserInfo();

            if (buGUID != null)
            {
                viewUser.DefaultBuUnitGUID = buGUID;
            }

            if (applicationGUID != null)
            {
                viewUser.DefaultApplicationGUID = applicationGUID;
            }

            if (companyGUID != null)
            {
                viewUser.DefaultCompanyGUID = companyGUID;
            }

            // 写入cookie 获取token
            var token = this.IocResolver.Resolve<ITokenAuthService>().CreateAccessToken(viewUser);
            var seconds = (int)TimeSpan.FromMinutes(Convert.ToDouble(viewUser.TokenExpiryMinute == 0 ? 60 : viewUser.TokenExpiryMinute)).TotalSeconds - 60;

            CookieOptions options = new CookieOptions()
            {
                Expires = DateTime.Now.AddSeconds(seconds)
            };
            httpContext.Response.Cookies.Append("Abp.AuthToken", token, options);
        }
    }
}
